﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Diagnostics;

namespace LicenseAutoDetection
{
    public enum Work
    {
        Update,
        View
    }

   public class IgnoreFileList
   {
       public struct IgnoreFileINFO
       {
           public string fullpath;
           public string drive;
           public string extension;
           public string lastWriteTime;
       }
       
       const string DefaultXml = "IgnoreFiles.xml";
       const string RootTag = "root";
       const string ImgTag = "Img";
       static readonly string Query = "Img[@info=\"{0}\" and . = \"{1}\"]";
       static readonly string[] ExtTag = new string[] { "jpg", "jpeg", "png", "xls", "xlsx", "pdf" };

       XmlDocument xmlDoc;
       XmlNode rootNode;
       List<string> Ignored;
       IgnoreFileINFO fileInfo;

       public IgnoreFileList()
       {
           fileInfo = new IgnoreFileINFO();
           Ignored = new List<string>();
           xmlDoc = new XmlDocument();
           try
           {
               xmlDoc.Load(DefaultXml);
           }
           catch (System.IO.FileNotFoundException)
           {
               IgnoreFileListCreate();
           }
           rootNode = xmlDoc.DocumentElement;  
       }

       private void IgnoreFileListCreate()
       {
           //xmlDoc = new XmlDocument();
           xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "utf-8", "yes"));
           XmlNode root = xmlDoc.CreateElement(RootTag);
           xmlDoc.AppendChild(root);
       }

       private void CreateNode(XmlNode node)
       {
           foreach (string tag in ExtTag)
           {
               XmlNode child = xmlDoc.CreateElement(tag);
               node.AppendChild(child);
           }
       }

       private XmlNode CreateNode(string tag, IgnoreFileINFO fileInfo)
       {
           XmlElement element = xmlDoc.CreateElement(tag);
           element.SetAttribute("info", fileInfo.lastWriteTime);
           element.InnerText = fileInfo.fullpath;
           return element;
       }

       private XmlNode CreateNode(string tag)
       {
           XmlNode node = xmlDoc.CreateElement(tag);
           CreateNode(node);

           return node;
       }

       private XmlNode CreateDriveTag(string tag)
       {
           rootNode.AppendChild(CreateNode(tag));
           return rootNode.SelectSingleNode(tag);
       }

       private void ignoreFileInFo(string path)
       {
           FileInfo f = new FileInfo(path);
           string[] tok = Path.GetPathRoot(path).Split(':');
           fileInfo.fullpath = path;
           fileInfo.drive = tok[0].ToString();
           fileInfo.extension = Path.GetExtension(path).Substring(1, Path.GetExtension(path).Length - 1).ToLower();
           fileInfo.lastWriteTime = f.LastWriteTime.ToString();
       }

       public void addIgnoreFile(string path)
       {
           ignoreFileInFo(path);
           XmlNode driNode = rootNode.SelectSingleNode(fileInfo.drive);
           if (driNode == null)
               driNode = CreateDriveTag(fileInfo.drive);  // 노드 추가

           XmlNode extNode = driNode.SelectSingleNode(fileInfo.extension);
           extNode.AppendChild(CreateNode(ImgTag, fileInfo));
           
       }

       public Boolean existIgnoreFile(string path)
       {
           XmlNodeList nodeList;
           XmlNode driNode, extNode;
           string xPath;
           try
           {
               ignoreFileInFo(path);
               driNode = rootNode.SelectSingleNode(fileInfo.drive);
               if (driNode == null)
                   return false;

               extNode = driNode.SelectSingleNode(fileInfo.extension);
               xPath = string.Format(Query, fileInfo.lastWriteTime, fileInfo.fullpath);
               nodeList = extNode.SelectNodes(xPath);

               if (nodeList.Count > 0)
                   return true;
               else
                   return false;
           }
           catch(Exception e)
           {
               Debug.WriteLine(path + ": " + e.Message);
               return false;
           }
       }

       public void UpdateignoreFileList(XmlNode parentNode, Work mode)    
       {
           XmlNodeList childNode = parentNode.SelectNodes(ImgTag);
           foreach (XmlNode node in childNode)
           {
               if (mode == Work.View)
               {
                   Ignored.Add(node.InnerText);
               }
               else
               {
                   if (File.Exists(node.InnerText))
                   {
                       FileInfo f = new FileInfo(node.InnerText);
                       XmlNode nodeAttribute = node.Attributes.Item(0);
                       if (f.LastWriteTime.ToString().CompareTo(nodeAttribute.InnerText) != 0)
                           parentNode.RemoveChild(node);
                   }
                   else
                       parentNode.RemoveChild(node);
               }
           }
       }

       public void Delete(string path)
       {
           XmlNode driveNode, extNode;
           XmlNodeList childNode;
           try
           {
               ignoreFileInFo(path);
               driveNode = rootNode.SelectSingleNode(fileInfo.drive);
               extNode = driveNode.SelectSingleNode(fileInfo.extension);
               childNode = extNode.SelectNodes(ImgTag);
               foreach (XmlNode node in childNode)
               {
                   if(path.CompareTo(node.InnerText.ToString()) == 0)
                       extNode.RemoveChild(node);
               }
               
           }
           catch
           {

           }
       }

       public string[] View()
       {
           Ignored.Clear();
           Update(Work.View);
           return Ignored.ToArray();
       }

       public void Update(Work mode)         
       {
           foreach (XmlNode driveNode in rootNode.ChildNodes)
           {
               foreach (XmlNode extNode in driveNode.ChildNodes)
               {
                   UpdateignoreFileList(extNode, mode);
               }
           }
           Save();
       }

       public void Save()
       {
           xmlDoc.Save(DefaultXml);
       }
    }
}
